#include "pch.hpp"
#include "KeyboardHookHelper.hpp"

#include <boostext/smart_ptr.hpp>




// That is the ONLY instance of the KeyboardHookHelper class
// If anyone (especially myself) creates a second one, the
// application will crash and slap the programmer.
// That instance however is created lazy, meaning that the hook
// is installed when the first MouseHook is created and uninstalled
// when there are no more MouseHook instances
boostext::smart_ptr<KeyboardHookHelper> m_keyboardHook;




KeyboardHookHelper::KeyboardHookHelper()
	: Hook(&keyboardHook)
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

KeyboardHookHelper::~KeyboardHookHelper()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////




LRESULT KeyboardHookHelper::keyboardProc(int nCode, WPARAM wParam, LPARAM lParam) const
{
	// "If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function
	// without further processing and should return the value returned by CallNextHookEx."
	// MSDN - http://msdn.microsoft.com/en-us/library/ms644984(VS.85).aspx
	if(nCode == HC_ACTION)
	{
		// lParam: Keystroke message flags, Transition-State Flag [31]
		// Specifies the transition state. The value is 0 if the key is being pressed and 1 if it is being released.
		// MSDN - http://msdn.microsoft.com/en-us/library/ms646267(VS.85).aspx
		int message = (lParam & 0x80000000) ? WM_KEYUP : WM_KEYDOWN;

		foreach(const KeyboardHook *hook, m_hooks)
		{
			hook->keyboardProc(message, wParam, lParam);
		}
	}

	// It is advised to always return CallNextHookEx, and not what windowProc actually
	return CallNextHookEx(m_hookHandle, nCode, wParam, lParam);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

LRESULT KeyboardHookHelper::keyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
{
	// The pointer throws on its own when it's empty
	return m_keyboardHook->keyboardProc(nCode, wParam, lParam);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
